﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace LpbPrj.Client.Tools.Helper
{
    public class ImageShareHelper
    {
        public static ImageCodecInfo imageCodecInfo = GetEncoderInfo();
        public static EncoderParameters encoderParameters = GetEncoderParameters();

        public static BitmapImage File2BitmapImage(string path)
        {
            if (!string.IsNullOrEmpty(path) && File.Exists(path) && (Path.GetExtension(path).Equals(".bmp") || Path.GetExtension(path).Equals(".jpeg") || Path.GetExtension(path).Equals(".jpg") || Path.GetExtension(path).Equals(".png")))
            {
                BitmapImage bitmap = new BitmapImage();
                bitmap.BeginInit();
                bitmap.CacheOption = BitmapCacheOption.OnLoad;
                bitmap.StreamSource = new MemoryStream(File.ReadAllBytes(path));
                bitmap.EndInit();
                bitmap.Freeze();
                return bitmap;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 刷新图像，直接将byte[]转换成WriteableBitmap进行展示
        /// </summary>
        public static void UpdateBitmap(WriteableBitmap bitmap, Int32Rect rect, byte[] pixels)
        {
            if (bitmap == null) throw new ArgumentNullException(nameof(bitmap));

            //// 1、低效率
            //pixels = Enumerable.Repeat((byte)new Random().Next(0, 255), rect.Width * rect.Height * bitmap.Format.BitsPerPixel / 8).ToArray();
            //bitmap.WritePixels(rect, pixels, rect.Width * bitmap.Format.BitsPerPixel / 8, 0);

            // 2、高效率
            bitmap.Lock();
            Marshal.Copy(pixels, 0, bitmap.BackBuffer, pixels.Length);
            bitmap.AddDirtyRect(rect);
            bitmap.Unlock();
        }

        /// <summary>
        /// Bitmap 裁剪
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Bitmap BitmapCut(Bitmap src, Rectangle cropRect)
        {
            Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
            }
            return target;
        }
        /// <summary>
        /// WriteableBitmap构建Bitmap
        /// WriteableBitmap继承自BitmapSource,可以直接保存到流中.然后,您从此流构建一个位图
        /// </summary>
        /// <param name="writeBmp"></param>
        /// <returns></returns>
        public static Bitmap BitmapFromWriteableBitmap(WriteableBitmap writeBmp)
        {
            Bitmap bmp;
            using (MemoryStream outStream = new MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(writeBmp));
                enc.Save(outStream);
                bmp = new Bitmap(outStream);
            }
            return bmp;
        }
        /// <summary>
        /// byte[]转为BitmapImage
        /// </summary>
        /// <param name="byteArray"></param>
        /// <returns></returns>
        public static BitmapImage ByteArray2BitmapImage(byte[] byteArray)
        {
            BitmapImage bmp = null;

            try
            {
                bmp = new BitmapImage();
                bmp.BeginInit();
                bmp.StreamSource = new MemoryStream(byteArray);
                bmp.EndInit();
            }
            catch
            {
                bmp = null;
            }

            return bmp;
        }
        /// <summary>
        /// BitmapImage转为byte[]
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static byte[] BitmapImage2ByteArray(BitmapImage bmp)
        {
            byte[] ByteArray = null;

            try
            {
                Stream stream = bmp.StreamSource;
                if (stream != null && stream.Length > 0)
                {
                    stream.Position = 0;
                    using (BinaryReader br = new BinaryReader(stream))
                    {
                        ByteArray = br.ReadBytes((int)stream.Length);
                    }
                }
            }
            catch
            {
                return null;
            }

            return ByteArray;
        }


        /// <summary>
        /// Bitmap存储高质量缩略图
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="thumbWidth"></param>
        /// <param name="thumbHeight"></param>
        /// <param name="bmpFilePath"></param>
        public static void GetThumbBitmapImage(Bitmap bmp, int thumbWidth, int thumbHeight, string bmpFilePath, ImageFormat imageFormat = null)
        {
            if (imageFormat == null)
            {
                using (Bitmap bmpThumb = new Bitmap(thumbWidth, thumbHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
                {
                    using (Graphics gThumb = Graphics.FromImage(bmpThumb))
                    {
                        //设置高质量插值法
                        gThumb.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                        //设置高质量,低速度呈现平滑程度
                        gThumb.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //设置高质量合成图像
                        gThumb.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        //清空画布并以透明背景色填充
                        gThumb.Clear(System.Drawing.Color.Transparent);

                        gThumb.DrawImage(bmp, new Rectangle(0, 0, thumbWidth, thumbHeight), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
                    }
                    bmpThumb.Save(bmpFilePath, ImageFormat.Jpeg);
                }
            }
            else
            {
                using (Bitmap bmpThumb = new Bitmap(thumbWidth, thumbHeight, bmp.PixelFormat))
                {
                    using (Graphics gThumb = Graphics.FromImage(bmpThumb))
                    {
                        //设置高质量插值法
                        gThumb.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                        //设置高质量,低速度呈现平滑程度
                        gThumb.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //设置高质量合成图像
                        gThumb.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        //清空画布并以透明背景色填充
                        gThumb.Clear(System.Drawing.Color.Transparent);

                        gThumb.DrawImage(bmp, new Rectangle(0, 0, thumbWidth, thumbHeight), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
                    }
                    if (imageFormat == null)
                    {
                        imageFormat = ImageFormat.Jpeg;
                    }
                    bmpThumb.Save(bmpFilePath, imageFormat);
                }
            }
        }

        public static void GetThumbBitmapImage(string bmpFileName, int thumbWidth, string bmpFilePath)
        {
            if (string.IsNullOrEmpty(bmpFileName) || string.IsNullOrEmpty(bmpFilePath) || !File.Exists(bmpFileName) || thumbWidth <= 0) return;

            using (Bitmap bmp = new Bitmap(bmpFileName))
            {
                int thumbHeight = (int)(thumbWidth * 1.0 / bmp.Width * bmp.Height);
                using (Bitmap bmpThumb = new Bitmap(thumbWidth, thumbHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
                {
                    using (Graphics gThumb = Graphics.FromImage(bmpThumb))
                    {
                        //设置高质量插值法
                        gThumb.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                        //设置高质量,低速度呈现平滑程度
                        gThumb.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        //设置高质量合成图像
                        gThumb.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        //清空画布并以透明背景色填充
                        gThumb.Clear(System.Drawing.Color.Transparent);

                        gThumb.DrawImage(bmp, new Rectangle(0, 0, thumbWidth, thumbHeight), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
                    }
                    bmpThumb.Save(bmpFilePath, ImageFormat.Jpeg);
                }
            }
        }

        /// <summary>
        /// Bmp原路径保存为Jpg
        /// </summary>
        /// <param name="bmpPath"></param>
        public static void BmpSaveToJpg(string bmpPath)
        {
            string jpgPath = bmpPath.Replace(".bmp", ".jpg");

            BitmapImage bitImage = new BitmapImage(new Uri(bmpPath, UriKind.Absolute));
            JpegBitmapEncoder encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitImage));
            using (FileStream fileStream = new FileStream(jpgPath, FileMode.Create, FileAccess.ReadWrite))
            {
                encoder.Save(fileStream);
                fileStream.Close();
            }
        }

        /// <summary>
        /// 获取编码格式
        /// </summary>
        /// <param name="mimeType"></param>
        /// <returns></returns>
        public static ImageCodecInfo GetEncoderInfo(string mimeType = "image/jpeg")
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }
        /// <summary>
        /// 获取编码参数
        /// </summary>
        /// <returns></returns>
        public static EncoderParameters GetEncoderParameters()
        {
            // for the Quality parameter category.
            // EncoderParameter object in the array.
            var myEncoderParameters = new EncoderParameters(1);
            //设置质量 数字越大质量越好，但是到了一定程度质量就不会增加了，MSDN上没有给范围，只说是32为非负整数
            myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);

            return myEncoderParameters;
        }




        /// <summary>
        /// 控件转换成图像，截图
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="visual"></param>
        /// <param name="actualWidth"></param>
        /// <param name="actualHeight"></param>
        /// <param name="format"></param>
        public static void Visual2Image(string fileName, Visual visual, int actualWidth, int actualHeight, ImageType format = ImageType.Jpg)
        {
            if (File.Exists(fileName)) File.Delete(fileName);

            RenderTargetBitmap targetBitmap = new RenderTargetBitmap(actualWidth, actualHeight, 96d, 96d, PixelFormats.Default);
            targetBitmap.Render(visual);

            BitmapEncoder saveEncoder = null;

            switch (format)
            {
                case ImageType.Jpg:
                    saveEncoder = new JpegBitmapEncoder();
                    break;
                case ImageType.Png:
                    saveEncoder = new PngBitmapEncoder();
                    break;
                case ImageType.Bmp:
                    saveEncoder = new BmpBitmapEncoder();
                    break;
                case ImageType.Gif:
                    saveEncoder = new GifBitmapEncoder();
                    break;
                case ImageType.Tif:
                    saveEncoder = new TiffBitmapEncoder();
                    break;
                default:
                    throw new InvalidOperationException();
            }

            saveEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
            using (FileStream fs = File.Open(fileName, FileMode.OpenOrCreate))
            {
                saveEncoder.Save(fs);
            }
        }
        /// <summary>
        /// 控件转换成Bitmap
        /// </summary>
        /// <param name="visual"></param>
        /// <param name="actualWidth"></param>
        /// <param name="actualHeight"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static Bitmap Visual2Bitmap(Visual visual, int actualWidth, int actualHeight, ImageType format = ImageType.Jpg)
        {
            RenderTargetBitmap targetBitmap = new RenderTargetBitmap(actualWidth, actualHeight, 96d, 96d, PixelFormats.Default);
            targetBitmap.Render(visual);

            BitmapEncoder saveEncoder = null;

            switch (format)
            {
                case ImageType.Jpg:
                    saveEncoder = new JpegBitmapEncoder();
                    break;
                case ImageType.Png:
                    saveEncoder = new PngBitmapEncoder();
                    break;
                case ImageType.Bmp:
                    saveEncoder = new BmpBitmapEncoder();
                    break;
                case ImageType.Gif:
                    saveEncoder = new GifBitmapEncoder();
                    break;
                case ImageType.Tif:
                    saveEncoder = new TiffBitmapEncoder();
                    break;
                default:
                    throw new InvalidOperationException();
            }

            saveEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
            using (MemoryStream stream = new MemoryStream())
            {
                saveEncoder.Save(stream);
                return new Bitmap(stream);
            }
        }
        /// <summary>
        /// 控件转换成byte[]
        /// </summary>
        /// <param name="visual"></param>
        /// <param name="actualWidth"></param>
        /// <param name="actualHeight"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static byte[] Visual2Bytes(Visual visual, int actualWidth, int actualHeight, ImageType format = ImageType.Jpg)
        {
            RenderTargetBitmap targetBitmap = new RenderTargetBitmap(actualWidth, actualHeight, 96d, 96d, PixelFormats.Default);
            targetBitmap.Render(visual);

            BitmapEncoder saveEncoder = null;

            switch (format)
            {
                case ImageType.Jpg:
                    saveEncoder = new JpegBitmapEncoder();
                    break;
                case ImageType.Png:
                    saveEncoder = new PngBitmapEncoder();
                    break;
                case ImageType.Bmp:
                    saveEncoder = new BmpBitmapEncoder();
                    break;
                case ImageType.Gif:
                    saveEncoder = new GifBitmapEncoder();
                    break;
                case ImageType.Tif:
                    saveEncoder = new TiffBitmapEncoder();
                    break;
                default:
                    throw new InvalidOperationException();
            }

            saveEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
            using (MemoryStream stream = new MemoryStream())
            {
                saveEncoder.Save(stream);
                return stream.ToArray();
            }

        }
        public enum ImageType { Jpg, Bmp, Png, Gif, Tif }

        /// <summary>
        /// 不可用的
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        [Obsolete("不推荐使用")]
        public static InteropBitmap Bitmap2WriteableBitmap(Bitmap bitmap)
        {
            if (bitmap == null) throw new ArgumentNullException(nameof(bitmap));

            var width = bitmap.Width;
            var height = bitmap.Height;
            var rBitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

            return Imaging.CreateBitmapSourceFromMemorySection(rBitmapData.Scan0,
                    width, height, PixelFormats.Bgr24, width * PixelFormats.Bgr24.BitsPerPixel / 8, 0) as InteropBitmap;

        }


        /// <summary>
        /// Bitmap转换成BitmapImage
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
        {
            BitmapImage bitmapImage = new BitmapImage();
            using (MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Bmp);
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = ms;
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.EndInit();
                bitmapImage.Freeze();
            }
            return bitmapImage;
        }
        /// <summary>
        /// BitmapImage转换成Bitmap
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static Bitmap BitmapImageToBitmap(BitmapImage bitmap)
        {
            Bitmap bmp = new Bitmap(bitmap.PixelWidth, bitmap.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

            BitmapData data = bmp.LockBits(
                new Rectangle(System.Drawing.Point.Empty, bmp.Size),
                ImageLockMode.WriteOnly,
                System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

            bitmap.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
            bmp.UnlockBits(data);
            return bmp;
        }


        [DllImport("Gdi32.dll")]
        private static extern bool DeleteObject(IntPtr hObject);
        /// <summary>
        /// 将 Bitmap 转化为 BitmapSource
        /// </summary>
        /// <param name="bmp"/>要转换的 Bitmap
        /// <returns>转换后的 BitmapSource</returns>
        public static BitmapSource ToBitmapSource(Bitmap bmp)
        {
            IntPtr hBitmap = bmp.GetHbitmap();
            try
            {
                return Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(hBitmap);
            }
        }
        /// <summary>
        /// 将 BitmapSource 转化为 Bitmap
        /// </summary>
        /// <param name="source"/>要转换的 BitmapSource
        /// <returns>转化后的 Bitmap</returns>
        public static Bitmap ToBitmap(BitmapSource source)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BitmapEncoder encoder = new BmpBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(source));
                encoder.Save(ms);
                return new Bitmap(ms);
            }
        }





        /// <summary>
        /// 截屏保存为图像jpg
        /// </summary>
        /// <param name="point"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="fileName"></param>
        public static void CopyFromScreen2Image(System.Windows.Point point, int width, int height, string fileName)
        {
            if (File.Exists(fileName)) File.Delete(fileName);

            //创建图象，保存将来截取的图象
            using (Bitmap image = new Bitmap(width, height))
            {
                using (Graphics imgGraphics = Graphics.FromImage(image))
                {
                    //设置高质量插值法
                    imgGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                    //设置高质量,低速度呈现平滑程度
                    imgGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    //设置高质量合成图像
                    imgGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    //清空画布并以透明背景色填充
                    imgGraphics.Clear(System.Drawing.Color.Transparent);

                    //设置截屏区域
                    imgGraphics.CopyFromScreen((int)point.X, (int)point.Y, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);
                }
                //保存
                image.Save(fileName, ImageFormat.Jpeg);
            }
        }
        /// <summary>
        /// 截屏保存成Bitmap
        /// </summary>
        /// <param name="point"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Bitmap CopyFromScreen2Image(System.Windows.Point point, int width, int height)
        {
            //创建图象，保存将来截取的图象
            Bitmap image = new Bitmap(width, height);
            using (Graphics imgGraphics = Graphics.FromImage(image))
            {
                //设置高质量插值法
                imgGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                //设置高质量,低速度呈现平滑程度
                imgGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //设置高质量合成图像
                imgGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                //清空画布并以透明背景色填充
                imgGraphics.Clear(System.Drawing.Color.Transparent);

                //设置截屏区域
                imgGraphics.CopyFromScreen((int)point.X, (int)point.Y, 0, 0, new System.Drawing.Size(width, height));
            }

            return image;
        }
        /// <summary>
        /// 获取控件相对屏幕的位置
        /// </summary>
        /// <param name="element">元素或者控件</param>
        /// <param name="relativeToScreen">是否相对屏幕</param>
        /// <returns></returns>
        public static Rect GetAbsolutePlacement(FrameworkElement element, bool relativeToScreen = true)
        {
            var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0));
            if (relativeToScreen)
            {
                return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
            }
            var posMW = Application.Current.MainWindow.PointToScreen(new System.Windows.Point(0, 0));
            absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y);
            return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight);
        }






        /// <summary>
        /// 将 Bitmap 转化为字节数组
        /// </summary>
        /// <param name="bmp">要转换的 Bitmap</param>
        /// <returns>转换后的字节数组</returns>
        public static byte[] ToByteArray(Bitmap bmp)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bmp.Save(stream, ImageFormat.Bmp);
                byte[] data = new byte[stream.Length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(data, 0, Convert.ToInt32(stream.Length));
                return data;
            }
        }


        /// <summary>
        /// 将 Bitmap 转化为字节数组
        /// </summary>
        /// <param name="bmp">要转换的 Bitmap</param>
        /// <returns>转换后的字节数组</returns>
        public static byte[] JpgToBmp(string filePath)
        {
            //using (MemoryStream stream = new MemoryStream())
            //{
            //    bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
            //    byte[] data = new byte[stream.Length];
            //    stream.Seek(0, SeekOrigin.Begin);
            //    stream.Read(data, 0, Convert.ToInt32(stream.Length));
            //    return data;
            //}

            byte[] bytes = null;

            using (Bitmap bitmap = new Bitmap(filePath))
            {
                //BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppArgb1555);
                //using (Bitmap bitmap2 = new Bitmap(bitmap.Width, bitmap.Height, data.Stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, data.Scan0))
                //{
                //    bitmap2.Save(@"E:\Desert.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
                //    bitmap.UnlockBits(data);
                //}
                bytes = new byte[bitmap.Width * bitmap.Height * 3];
                int wide = bitmap.Width;
                int i = 0;
                int height = bitmap.Height;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < wide; x++)
                    {
                        var srcColor = bitmap.GetPixel(x, y);
                        //bytes[i] = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114);
                        bytes[i] = srcColor.R;
                        i++;
                        bytes[i] = srcColor.G;
                        i++;
                        bytes[i] = srcColor.B;
                        i++;
                    }
                }
            }

            return bytes;
        }




        /// <summary>
        /// 将源图像灰度化，并转化为8位灰度图像。
        /// </summary>
        /// <param name="original"> 源图像。 </param>
        /// <returns> 8位灰度图像。 </returns>
        public static Bitmap RgbToGrayScale(Bitmap original)
        {
            if (original != null)
            {
                // 将源图像内存区域锁定
                Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);
                BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                // 获取图像参数
                int width = bmpData.Width;
                int height = bmpData.Height;
                int stride = bmpData.Stride;  // 扫描线的宽度,比实际图片要大
                int offset = stride - width * 3;  // 显示宽度与扫描线宽度的间隙
                IntPtr ptr = bmpData.Scan0;   // 获取bmpData的内存起始位置的指针
                int scanBytesLength = stride * height;  // 用stride宽度，表示这是内存区域的大小

                // 分别设置两个位置指针，指向源数组和目标数组
                int posScan = 0, posDst = 0;
                byte[] rgbValues = new byte[scanBytesLength];  // 为目标数组分配内存
                Marshal.Copy(ptr, rgbValues, 0, scanBytesLength);  // 将图像数据拷贝到rgbValues中
                                                                   // 分配灰度数组
                byte[] grayValues = new byte[width * height]; // 不含未用空间。
                                                              // 计算灰度数组

                byte blue, green, red;



                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {

                        blue = rgbValues[posScan];
                        green = rgbValues[posScan + 1];
                        red = rgbValues[posScan + 2];
                        grayValues[posDst] = (byte)((blue + green + red) / 3);
                        posScan += 3;
                        posDst++;

                    }
                    // 跳过图像数据每行未用空间的字节，length = stride - width * bytePerPixel
                    posScan += offset;
                }

                // 内存解锁
                Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);
                original.UnlockBits(bmpData);  // 解锁内存区域

                // 构建8位灰度位图
                Bitmap retBitmap = ToGrayBitmap(grayValues, width, height);
                return retBitmap;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 获取8位位图的调色板
        /// </summary>
        /// <returns></returns>
        public static ColorPalette GetbmpGay8Palette(int? alpha = 255, int? red = null, int? green = null, int? blue = null)
        {
            // 修改生成位图的索引表，从伪彩修改为灰度
            ColorPalette palette;
            // 获取一个Format8bppIndexed格式图像的Palette对象
            using (Bitmap bmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed))
            {
                palette = bmp.Palette;
            }
            for (int i = 0; i < 256; i++)
            {
                palette.Entries[i] = System.Drawing.Color.FromArgb(
                    alpha.HasValue ? alpha.Value : i,
                    red.HasValue ? red.Value : i,
                    green.HasValue ? green.Value : i,
                    blue.HasValue ? blue.Value : i);
            }

            return palette;
        }

        /// <summary>  
        /// 用灰度数组新建一个8位灰度图像  
        /// </summary>  
        /// <param name="rawValues">显示字节数组</param>  
        /// <param name="width">图像宽度</param>  
        /// <param name="height">图像高度</param>  
        /// <returns>位图</returns>  
        public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height, ColorPalette bmpGay8Palette = null)
        {
            // 申请目标位图的变量，并将其内存区域锁定  
            Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

            // 获取图像参数  
            int stride = bmpData.Stride;  // 扫描线的宽度  
            int offset = stride - width;  // 显示宽度与扫描线宽度的间隙  
            IntPtr iptr = bmpData.Scan0;  // 获取bmpData的内存起始位置  
            int scanBytes = stride * height;// 用stride宽度，表示这是内存区域的大小  

            // 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组  
            int posScan = 0, posReal = 0;// 分别设置两个位置指针，指向源数组和目标数组  
            byte[] pixelValues = new byte[scanBytes];  //为目标数组分配内存  

            for (int x = 0; x < height; x++)
            {
                //// 下面的循环节是模拟行扫描  
                for (int y = 0; y < width; y++)
                {
                    pixelValues[posScan++] = rawValues[posReal++];
                }
                posScan += offset;  //行扫描结束，要将目标位置指针移过那段“间隙”  
            }

            //// 用Marshal的Copy方法，将刚才得到的内存字节数组复制到BitmapData中  
            Marshal.Copy(pixelValues, 0, iptr, scanBytes);
            bmp.UnlockBits(bmpData);  // 解锁内存区域  

            bmp.Palette = bmpGay8Palette == null ? GetbmpGay8Palette() : bmpGay8Palette;

            // 算法到此结束，返回结果  
            return bmp;
        }

        /// <summary>
        /// 将字节数组转换为位图
        /// </summary>
        /// <param name="rawValues"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="pixelFormat"></param>
        /// <returns></returns>
        public static Bitmap Bytes2Bitmap(byte[] rawValues, int width, int height, ColorPalette bmpGay8Palette, System.Drawing.Imaging.PixelFormat pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
        {
            Bitmap bmp = new Bitmap(width, height, pixelFormat);
            if (pixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
            {
                bmp.Palette = bmpGay8Palette;
            }
            BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat);
            Marshal.Copy(rawValues, 0, bitmapData.Scan0, rawValues.Length);
            bmp.UnlockBits(bitmapData);
            return bmp;
        }





        /// <summary>
        /// 在原始图像上绘制圆
        /// IolMaster使用
        /// </summary>
        /// <param name="bmpSrcPath">原始图像地址</param>
        /// <param name="bmpSavePath">生成图像保存的地址</param>
        /// <param name="centerX">X坐标 像素</param>
        /// <param name="centerY">Y坐标 像素</param>
        /// <param name="diameter">直径 像素</param>
        /// <param name="imageCircle">是否绘制圆标记</param>
        /// <returns></returns>
        public static bool BmpAddCircle(string bmpSrcPath, string bmpSavePath, string bmpThumbSavePath, int thumbWidth, System.Drawing.Pen pen, double? centerX, double? centerY, double? diameter, bool imageCircle = true)
        {
            if (string.IsNullOrEmpty(bmpSrcPath) || string.IsNullOrEmpty(bmpSavePath) || string.IsNullOrEmpty(bmpThumbSavePath) || !centerX.HasValue || !centerY.HasValue || !diameter.HasValue) return false;
            if (!File.Exists(bmpSrcPath)) return false;

            try
            {
                using (Bitmap bmpSrc = new Bitmap(bmpSrcPath))
                {
                    using (Bitmap bmp = new Bitmap(bmpSrc.Width, bmpSrc.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
                    {
                        using (Graphics gThumb = Graphics.FromImage(bmp))
                        {
                            //设置高质量插值法
                            gThumb.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                            //设置高质量,低速度呈现平滑程度
                            gThumb.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            //设置高质量合成图像
                            gThumb.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                            //画原来的图像
                            gThumb.DrawImage(bmpSrc, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmpSrc.Width, bmpSrc.Height, GraphicsUnit.Pixel);
                            //画圆
                            if (imageCircle)
                            {
                                gThumb.DrawEllipse(pen, new Rectangle((int)(centerX.Value - diameter.Value * 0.5), (int)(centerY.Value - diameter.Value * 0.5), (int)diameter.Value, (int)diameter.Value));
                            }
                            else
                            {
                                gThumb.DrawLine(pen, (float)(centerX.Value - diameter.Value * 0.5), (float)(bmp.Height * 0.25), (float)(centerX.Value - diameter.Value * 0.5), (float)(bmp.Height * 0.75));
                                gThumb.DrawLine(pen, (float)(centerX.Value + diameter.Value * 0.5), (float)(bmp.Height * 0.25), (float)(centerX.Value + diameter.Value * 0.5), (float)(bmp.Height * 0.75));
                            }
                        }
                        bmp.Save(bmpSavePath, ImageFormat.Jpeg);

                        int thumbHeight = (int)(thumbWidth * 1.0 / bmp.Width * bmp.Height);
                        GetThumbBitmapImage(bmp, thumbWidth, thumbHeight, bmpThumbSavePath);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"BmpAddCircle Error: {ex.Message}");
                System.Diagnostics.Debug.WriteLine($"BmpAddCircle Error: {ex.StackTrace}");
                return false;
            }

            return true;
        }


    }
}
